#ifndef IBC_H
#define IBC_H


#include <omnithread.h>

// iostream cout is going to be used for tracing.
#include <iostream>
#include <assert.h>



/*
 * Invoker of Background Commands (IBC)
 * @author Nebojsa Trninic
 * @date   07.09.2012.
 *
 * The purpose of this module is to allow users to create arbitrary commands, derived
 * from ICommand and then use CInvokerBackgroundCommands to execute them in background 
 * thread, so that if command needs more time to execute than the time given by the user,
 * the main thread continues while invoker and background thread handle resource 
 * deallocation.
 *
 */

namespace IBC
{


    typedef omni_mutex      CMutex;
    typedef omni_mutex_lock CMutexLock;
    typedef omni_condition  CCondition;
    typedef omni_thread     CThread;



class ICommand
{
    // Command interface should be used to derive Command classes that implement
    // operations needed to be executed in background. Once these are implemented
    // they can be passed to Invoker of Background Commands that handles their 
    // execution in background thread and later on resource deallocation, both in
    // case of in time command execution and in case when a timeout occurs.
 public:
    enum TCommandState
    {
        CS_S_INIT,         // Just created.
        CS_S_PARAMSSET,    // Params have been set.
        CS_S_EXEC_OK,      // Execution done, results ready.
        CS_E_EXEC_ERR,     // Execution done, error occurred.
        CS_E_EXEC_EXC      // Execution done, exception occurred.
    }; // enum TCommandState

    ICommand() : m_nCommandState( CS_S_INIT ), m_pExc( NULL ) {  };
    virtual ~ICommand() { if( m_pExc != NULL ) { delete m_pExc; m_pExc = NULL; } };

    // Command state changes as its life cycle goes, i.e. methods are called.
    TCommandState getCommandState( void ) { return m_nCommandState; };

    // Remember to implement parameter get/set methods. Set should update Cmd state
    // attribute to CS_S_PARAMSSET. Get should consult it and in case they were not set, inform
    // the caller.
    // ... getParams( void ) = 0;
    // void setParams( ... ) = 0;

    virtual void execute( void )= 0; // Called in order for command to be executed. Params
                                     // should have been set. User command should catch all
                                     // exceptions that occur and pack them in case they
                                     // do. Also in case of error it should be packed. In
                                     // case of success results should be packed. Command state
                                     // attribute should be updated to reflect what happend:
                                     // success, error or exception.

    // Remember to implement result/error handling methods.
    // ... getResults( void ) = 0; // OK or error and result values.

    std::exception *getException( void ) { return m_pExc; } ;

 protected:
    TCommandState   m_nCommandState; // Command state attribute.
    std::exception  *m_pExc; // In case of exception during execute(), its copy is going to be 
                             // allocated in heap and stored here. execute() method needs to pack it.
}; // class ICommand


// Forward declaration.
class CBackgroundThread;

/*
 * CInvokerBackgroundCommands
 * No classes should be derived from this one, this one is intended to be used as it is.
 * Invoker owns both Bg thread and command. The goal is to have command executed in Bg thread, while
 * the main invoker thread awaits for the execution to complete, but not longer than the specified
 * timeout value. If the command executes in time, the main thread can use command result/error/exception.
 * If the command takes too long to execute, depending on timeout policy (linger, kill), Bg thread is
 * either left to linger (take as much time as needed for the command to complete) or killed (if supported
 * by the threading library that is used, in which case resource deallocation needs to be taken care
 * of carefully).
 */

class CInvokerBackgroundCommands
{
 public:
    enum TInvokerState
    {
        IS_S_PENDING,         // Bg thread still not started, but command is pending for execution.
        IS_S_INEXEC,          // Bg thread started.
        IS_S_DONE,            // Bg thread finished, see command for result/error/exception.
        IS_E_RESOURCES,       // Problems with resource (memory, command object, thread, etc)
                              // allocation. *** Do not touch command.
        IS_E_TIMEOUT_KILLED,  // Bg thread killed after timeout.  *** Do not touch command.
        IS_E_TIMEOUT_LINGER   // Timeout occured, Bg thread left running 
                              // executing command.  *** Do not touch command.
    }; // enum TInvokerState

    enum TInvokerTimeoutPolicy
    {
        TOP_LINGER, // In case of timeout, leave Bg thread to run until it finishes.
        TOP_KILL    // In case of timeout, kill Bg thread.
    }; // enum TInvokerTimeoutPolicy
    
    CInvokerBackgroundCommands( unsigned long         v_nTO,      // Desired command execution time in [seconds].
                                TInvokerTimeoutPolicy v_nTOP,     // TimeOut Policy.
                                ICommand              *v_pCmd ) : // Which command to execute.

        m_nInvokerState( IS_S_PENDING ), // Upon construction command is pending to be executed.
        m_nTOpolicy    ( v_nTOP ),       // TimeOut Policy.
        m_nTO          ( v_nTO ),        // Timeout in seconds.
        m_pCmd         ( v_pCmd ),       // Memorize command.
        m_nRC          ( 1 ),            // When initialized Invoker ref. count is 1 and this is main
                                         // thread reference to Invoker.
        m_pCndBgThr    ( NULL ),              // Condition will be allocated later in execCmdInBgThr().
        m_pThrBg       ( NULL ) { g_nRC++; }; // Bg thread will be allocated later in execCmdInBgThr().
        
    void execCmdInBgThr( void ); // Invoker starts Bg thread and command is executed. Updates
                                 // Invoker state which can be used to figure out how
                                 // successful this attempt was.

    TInvokerState getInvokerState( void ); // Retrieve Invoker state in thread safe manner.

    void RCinc( void ); // In case another thread claims access to invoker attributes,
                        // ref count needs to be incremented.

    void RCdec( void ); // In case when thread is not going to access invoker attributes
                        // anymore. E.g. main thread should make sure that it first
                        // processes/copies command results/errors/exceptions and only
                        // then decreases invoker RC, since once invoker RC goes from 1
                        // to 0 it is going to deallocate all its attributes including
                        // the command.

    unsigned char RCget( void ); // returns RC value in thread safe manner.

 private:
    friend class CBackgroundThread; // Bg thread needs to access invoker private attributes,
                                    // e.g. mutex, condition and command. So it must 
                                    // be friend of this class.

    CMutex                m_mtxInvSta; // Mutex for Invoker State attribute access. Access only through
                                       // get/set methods, since both main invoker and bg threads need it.
    TInvokerState         m_nInvokerState;
    void setInvokerState( TInvokerState v_nSta ); // Set Invoker state in thread safe manner. Private.

    TInvokerTimeoutPolicy m_nTOpolicy; // What to do with Bg thread in case of timeout.

    unsigned long m_nTO; // User specified TimeOut value [seconds]. Set when Invoker 
                         // is constructed. This is the
                         // time during which user wants command to be executed. If
                         // it is executed in this time Bg thread has finished, but if
                         // it has not, then main thread continues and handles this
                         // as an error, but Bg thread can be either killed or left to
                         // run, i.e. linger.

    ICommand *m_pCmd; // Pointer to command passed at construction time by Invoker user.
                      // The user wants the command executed in background thread. Execution
                      // time of main invoker thread should not exceed m_nTO value passed by the user.

    // Please note that command & other invoker attributes are referenced by both
    // main invoker thread and Bg thread, so invoker needs to be reference counted (RC).
    // Invoker is considered the owner of both command and Bg thread and should free
    // up resources including command and Bg thread once ref counter goes to 0.
    // RC is needed in case when Bg thread is left to linger and can finish at
    // a time when the main thread has given up waiting, but proper cleanup is needed
    // once lingering Bg thread finishes. To solve this, reference counting is used.
    // Invoker destructor needs to be private (i.e. it should not be possible 
    // for the user to delete invoker directly) and called only from RCdec(), once ref count
    // reaches zero. Main thread creates Invoker which starts with 1 in ref count
    // and Bg thread causes 1 to be added to ref count, so ref count can be 1 or 2.
    // Once ref. count goes from 1->0 it needs to delete Invoker, since it is not referenced
    // by anyone anymore.

    CMutex        m_mtxRC; // Mutex for ref count attribute access.
    unsigned char m_nRC;   // Reference Counting attribute. Access only through get/set methods, since
                           // both main invoker thread and bg threads need it.
    static unsigned char g_nRC; // Global ref count to determine global num of concurrent references.
                                // Can be used as an estimate of resource usage, i.e.
                                // contains the ones of lingering threads.

    ~CInvokerBackgroundCommands(); // Private destructor, so invoker cannot be explicitly
                                   // deleted by the user, but only through RC mechanism.

    // Attributes that are used for thread synchronization when accessing Invoker Command and Condition.
    CMutex        m_mtxCmdCond; // Invoker command and condition m_pCndBgThr attributes guard.
    CCondition    *m_pCndBgThr; // Condition to recognize BgThr finish, should relate to mutex m_mtxCmdCond.

    CBackgroundThread *m_pThrBg;    // Invoker background thread in which user command 
                                    // gets executed.

}; // class CInvokerBackgroundCommands


/*
 * CBackgroundThread
 * No classes should be derived from this one, this one is intended to be used as it is.
 * Invoker owns both command and Bg thread. Bg thread is intended to execute command owned by invoker.
 *
 */

class CBackgroundThread : public CThread
{
 public:
    CBackgroundThread( CInvokerBackgroundCommands *v_pIBC ) : m_pIBC( v_pIBC ) {};


 private:
    CInvokerBackgroundCommands *m_pIBC; // Pointer to Bg thread owner, i.e. invoker. Invoker owns
                                        // both command and Bg thread.

    virtual void run(void* /*arg*/); // Overloading run() to implement IBC needed features.
                                     // Goal is to execute Command given to Invoker by
                                     // this background thread. Needs private attributes
                                     // of Invoker for this, e.g. mutex, condition,
                                     // command and hence needs to be a friend of invoker.

}; // class CBackgroundThread


} // namespace IBC

#endif // IBC_H
